package com.im

import android.app.ActivityManager
import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.content.BroadcastReceiver
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.os.Build
import android.os.Bundle
import android.os.Handler.Callback
import android.os.Message
import android.text.TextUtils
import android.view.KeyEvent
import android.view.Menu
import android.view.MenuItem
import android.widget.Toast

import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.annotation.RequiresApi
import androidx.appcompat.app.AppCompatActivity
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.systemBarsPadding
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import androidx.constraintlayout.compose.ConstraintLayout
import androidx.core.content.ContextCompat

import com.common.InputBox
import com.common.MessageBox
import com.im.ui.theme.ImClientTheme

import java.util.Objects

import kotlin.system.exitProcess

// 主活动
class MainActivity: AppCompatActivity(), Callback, MenuItem.OnMenuItemClickListener {
    private lateinit var mClient: Client                    // 客户端
    private lateinit var mFriendCount: MutableState<String> // 好友数
    private lateinit var mInputBox: InputBox                // 输入窗口
    private lateinit var mListViewUsers: UserListView       // 好友列表控件
    private lateinit var mLogonDialog: LogonDialog          // 登录对话框
    private lateinit var mMenuItemAddFriend: MenuItem       // "添加好友"菜单项
    private lateinit var mMenuItemLogoff: MenuItem          // "离线"菜单项
    private lateinit var mMenuItemLogon: MenuItem           // "登录"菜单项
    private lateinit var mMenuItemMChat: MenuItem           // "群发消息"菜单项
    private lateinit var mMenuItemReg: MenuItem             // "注册"菜单项
    private lateinit var mMessageBox: MessageBox            // 消息窗口
    private lateinit var mStatus: MutableState<String>      // 登录状态

    /**
     * 添加所有好友到好友列表控件中。
     * @param result    登录结果
     */
    private fun addAllFriends(result: LogonResult) {
        for (i in 0 ..< result.mFriendCount) {
            this.addOneFriend(result.mFriends[i].mUsername, result.mFriends[i].mIconIndex, result.mFriendsOnline[i])
        }

        mFriendCount.value = super.getString(R.string.IDS_FRIEND_COUNT, result.mFriendCount)
    }

    /**
     * 添加一个好友到好友列表控件中。
     * @param friendName    好友名
     * @param iconIndex     好友头像索引
     * @param isOnline      好友在线则为 true，否则为 false
     */
    private fun addOneFriend(friendName: String, iconIndex: Int, isOnline: Boolean) {
        if (iconIndex < 0) {
            return
        }
        mListViewUsers.addItem(friendName, iconIndex, isOnline)
    }

    /**
     * 改变界面状态。
     * @param isLogon   已登录则为 true，否则为 false
     */
    private fun changeState(isLogon: Boolean) {
        mMenuItemLogon.isEnabled = !isLogon
        mMenuItemReg.isEnabled = !isLogon
        mMenuItemAddFriend.isEnabled = isLogon
        mMenuItemMChat.isEnabled = isLogon
        mMenuItemLogoff.isEnabled = isLogon

        mStatus.value = if (isLogon) super.getString(R.string.IDS_STATUS_LOGON) else super.getString(R.string.IDS_STATUS_LOGOFF)
        mFriendCount.value = super.getString(R.string.IDS_FRIEND_COUNT, 0)
    }

    /**
     * 获取结果信息。
     * @param resultCode    结果码
     * @return 结果信息
     */
    private fun getResultMessage(resultCode: ResultCode): String {
        return when (resultCode) {
            ResultCode.ADD_FRIEND_ALLOW -> super.getString(R.string.IDS_ADD_FRIEND_ALLOW)
            ResultCode.ADD_FRIEND_NOT_ALLOW -> super.getString(R.string.IDS_ADD_FRIEND_NOT_ALLOW)
            ResultCode.ALREADY_BE_FRIENDS -> super.getString(R.string.IDS_ALREADY_BE_FRIENDS)
            ResultCode.FRIEND_NAME_EQUAL_SELF_NAME -> super.getString(R.string.IDS_FRIEND_NAME_EQUAL_SELF_NAME)
            ResultCode.LOGON_SUCCEEDED -> super.getString(R.string.IDS_LOGON_SUCCEEDED)
            ResultCode.NETWORK_ERROR -> super.getString(R.string.IDS_NETWORK_ERROR)
            ResultCode.PASSWORD_WRONG -> super.getString(R.string.IDS_PASSWORD_WRONG)
            ResultCode.REG_SUCCEEDED -> super.getString(R.string.IDS_REG_SUCCEEDED)
            ResultCode.TOO_MANY_FRIENDS -> super.getString(R.string.IDS_TOO_MANY_FRIENDS)
            ResultCode.USER_ALREADY_LOGON -> super.getString(R.string.IDS_USER_ALREADY_LOGON)
            ResultCode.USER_EXISTS -> super.getString(R.string.IDS_USER_EXISTS)
            ResultCode.USER_NOT_FOUND -> super.getString(R.string.IDS_USER_NOT_FOUND)
            ResultCode.SUCCEEDED -> ""
        }
    }

    /**
     * 界面布局。
     */
    @Composable
    fun Greeting() {
        ConstraintLayout(Modifier
            .fillMaxSize()
            .systemBarsPadding()
        ) {
            // 初始化成员
            mFriendCount = remember {
                mutableStateOf(super.getString(R.string.IDS_FRIEND_COUNT, 0))
            }
            mStatus = remember {
                mutableStateOf(super.getString(R.string.IDS_STATUS_LOGOFF))
            }
            mInputBox.Greeting("")
            mLogonDialog.Greeting()
            mMessageBox.Greeting()

            val (statusBar) = this.createRefs()

            // 好友列表
            mListViewUsers.Greeting()

            // 状态栏
            Row(Modifier
                .background(Color.Black)
                .fillMaxWidth()
                .padding(Const.MAIN_ACTIVITY_STATUS_BAR_PADDING.dp)
                .constrainAs(statusBar) {
                    start.linkTo(parent.start)
                    bottom.linkTo(parent.bottom)
                }
            ) {
                // "状态"标签
                Text(
                    modifier = Modifier.weight(1f),
                    text = mStatus.value,
                    color = Color.White
                )
                // "好友数"标签
                Text(
                    modifier = Modifier.weight(1f),
                    text = mFriendCount.value,
                    color = Color.White
                )
            }
        }
    }

    /**
     * 处理自定义事件的方法。
     * @param message   事件
     * @return 事件在此被处理则返回 true，否则返回 false
     */
    override fun handleMessage(message: Message): Boolean {
        when (message.what) {
            Const.UM_CHAT_C2S -> {
                mClient.chat(message.obj as ChatInfo)
                return true
            }
            Const.UM_CHAT_S2C -> {
                this.onChatS2C(message.obj as ChatInfo)
                return true
            }
            Const.UM_FRIEND_LOGOFF -> {
                this.onFriendLogoff(message.obj as LogoffRequest)
                return true
            }
            Const.UM_FRIEND_LOGON -> {
                this.onFriendLogon(message.obj as FriendLogon)
                return true
            }
            Const.UM_GET_ADD_FRIEND_REQUEST -> {
                this.onGetAddFriendRequest(message.obj as AddFriendRequest)
                return true
            }
            Const.UM_GET_ADD_FRIEND_RESULT -> {
                this.onGetAddFriendResult(message.obj as AddFriendResult)
                return true
            }
            Const.UM_GET_LOGON_RESULT -> {
                this.onGetLogonResult(message.obj as LogonResult)
                return true
            }
            Const.UM_GET_REG_RESULT -> {
                this.onGetRegResult(message.obj as RegResult)
                return true
            }
            Const.UM_NETWORK_ERROR -> {
                mMessageBox.show(
                    tipText = super.getString(R.string.IDS_NETWORK_ERROR),
                    okButtonText = super.getString(android.R.string.ok),
                    onOK = {
                        exitProcess(0)
                    }
                )
                return true
            }
        }
        return false
    }

    /**
     * Activity 返回结果事件的响应方法。
     * @param requestCode   请求码
     * @param resultCode    结果码
     * @param intent        数据
     */
    @Deprecated("Deprecated in Java")
    override fun onActivityResult(requestCode: Int, resultCode: Int, intent: Intent?) {
        if (resultCode != RESULT_OK) {
            return
        }

        // 获取数据
        val bundle = intent?.extras

        // 根据请求码，做相应处理
        if (requestCode == Const.RC_REG) {
            checkNotNull(bundle)
            val username = bundle.getString(Const.KEY_USERNAME)
            val password = bundle.getString(Const.KEY_PASSWORD)
            val iconIndex = bundle.getInt(Const.KEY_ICON_INDEX)
            mClient.reg(username!!, password!!, iconIndex)
        }

        super.onActivityResult(requestCode, resultCode, intent)
    }

    /**
     * 聊天事件的响应方法（服务器到客户端）。
     * @param chatInfo  聊天信息
     */
    private fun onChatS2C(chatInfo: ChatInfo) {
        // 获取当前屏幕上显示的窗口的名称
        val activityManager = super.getSystemService(ACTIVITY_SERVICE) as ActivityManager
        val runningTaskInfoList = activityManager.getRunningTasks(1)
        var topActivityName: String? = null
        if (runningTaskInfoList != null) {
            topActivityName = Objects.requireNonNull<ComponentName?>(runningTaskInfoList[0].topActivity).className
        }

        // 获取好友名
        val isMultiChat = chatInfo.mDstUsername == ImProtocol.MULTI_CHAT
        val friendName = if (isMultiChat) chatInfo.mDstUsername else chatInfo.mSrcUsername

        // 生成意图
        val intent = Intent(this, ChatActivity::class.java)
        intent.putExtra(Const.KEY_FRIEND_NAME, friendName)
        intent.putExtra(Const.KEY_CHAT_INFO, chatInfo)

        if (ChatActivity::class.java.name == topActivityName && ChatActivity.friendName == friendName) {
            // 如果聊天窗口在屏幕上，并且发送聊天信息的好友是当前聊天窗口的好友，则直接显示聊天信息
            super.startActivity(intent)
        } else {
            // 创建系统通知
            val pendingIntent = PendingIntent.getActivity(this, Const.UM_CHAT_S2C, intent, PendingIntent.FLAG_UPDATE_CURRENT)
            val title = if (isMultiChat) chatInfo.mSrcUsername + " [ " + ImProtocol.MULTI_CHAT + " ]" else chatInfo.mSrcUsername
            val notification = Notification.Builder(this, Const.INTENT_CHAT_S2C)
                .setAutoCancel(true)
                .setContentTitle(title)
                .setContentText(chatInfo.mContent)
                .setSmallIcon(chatInfo.mSrcIconIndex + R.mipmap.normal00)
                .setContentIntent(pendingIntent)
                .build()

            // 发送通知，即在系统的通知栏上显示通知
            val manager = super.getSystemService(NOTIFICATION_SERVICE) as NotificationManager
            val channel = NotificationChannel(Const.INTENT_CHAT_S2C, ChatActivity::class.java.name, NotificationManager.IMPORTANCE_HIGH)
            manager.createNotificationChannel(channel)
            manager.notify(Const.NOTIFICATION_ID_CHAT, notification)
        }
    }

    /**
     * 创建事件的响应方法。
     * @param savedInstanceState    保存的实例状态
     */
    @RequiresApi(Build.VERSION_CODES.TIRAMISU)
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        this.enableEdgeToEdge()

        // 初始化成员
        mClient = Client(this)
        mInputBox = InputBox()
        mListViewUsers = UserListView(onItemClick, resources)
        mLogonDialog = LogonDialog()
        mMessageBox = MessageBox()

        // 设置内容
        this.setContent {
            ImClientTheme {
                this.Greeting()
            }
        }

        // 注册广播接收者，用来接收聊天窗口发送的聊天信息
        ContextCompat.registerReceiver(this, object: BroadcastReceiver() {
            /**
             * 接收到广播事件的响应方法。
             * @param context 设备环境
             * @param intent  意图
             */
            override fun onReceive(context: Context, intent: Intent) {
                val chatInfo = intent.getSerializableExtra(ChatInfo::class.java.name) as ChatInfo
                mClient.chat(chatInfo)
            }
        }, IntentFilter(Const.INTENT_CHAT_C2S), ContextCompat.RECEIVER_NOT_EXPORTED)

        // 暂停，等所有后台线程阻塞再继续执行
        // 如果此处不暂停，有可能导致无法登录
        try {
            Thread.sleep(100)
        } catch (e: InterruptedException) {
            e.printStackTrace()
        }
    }

    /**
     * 创建菜单事件的响应方法。
     * @param menu  菜单
     * @return 总是 true
     */
    override fun onCreateOptionsMenu(menu: Menu): Boolean {
        super.getMenuInflater().inflate(R.menu.main, menu)

        // 创建菜单项
        mMenuItemLogon = menu.findItem(R.id.IDC_MENU_ITEM_LOGON)
        mMenuItemReg = menu.findItem(R.id.IDC_MENU_ITEM_REG)
        mMenuItemAddFriend = menu.findItem(R.id.IDC_MENU_ITEM_ADD_FRIEND)
        mMenuItemMChat = menu.findItem(R.id.IDC_MENU_ITEM_MCHAT)
        mMenuItemLogoff = menu.findItem(R.id.IDC_MENU_ITEM_LOGOFF)

        // 菜单项添加事件监听者
        mMenuItemLogon.setOnMenuItemClickListener(this)
        mMenuItemReg.setOnMenuItemClickListener(this)
        mMenuItemAddFriend.setOnMenuItemClickListener(this)
        mMenuItemMChat.setOnMenuItemClickListener(this)
        mMenuItemLogoff.setOnMenuItemClickListener(this)

        return true
    }

    /**
     * 销毁事件的响应方法。
     */
    override fun onDestroy() {
        // 关闭客户端
        mClient.close()

        super.onDestroy()
    }

    /**
     * 好友离线事件的响应方法。
     * @param request   离线请求
     */
    private fun onFriendLogoff(request: LogoffRequest) {
        mListViewUsers.changeItemColor(request.mUsername, false)
    }

    /**
     * 好友登录事件的响应方法。
     * @param friendLogon   好友登录信息
     */
    private fun onFriendLogon(friendLogon: FriendLogon) {
        mListViewUsers.changeItemColor(friendLogon.mUsername, true)
    }

    /**
     * 得到添加好友请求事件的响应方法。
     * @param request   添加好友请求
     */
    private fun onGetAddFriendRequest(request: AddFriendRequest) {
        mMessageBox.show(
            tipText = request.mSrcUsername + super.getString(R.string.IDS_CONFIRM_ADD_FRIEND),
            cancelButtonText = super.getString(android.R.string.cancel),
            onCancel = {
                mClient.allowAddFriend(false, request)
            },
            okButtonText = super.getString(android.R.string.ok),
            onOK = {
                mClient.allowAddFriend(true, request)
                this.addOneFriend(request.mSrcUsername, request.mSrcIconIndex, true)
                mFriendCount.value = super.getString(R.string.IDS_FRIEND_COUNT, mClient.friendCount)
                ChatActivity.addFriend(request.mSrcUsername)
            }
        )
    }

    /**
     * 得到添加好友结果事件的响应方法。
     * @param result    添加好友结果
     */
    private fun onGetAddFriendResult(result: AddFriendResult) {
        var message = this.getResultMessage(result.mResultCode)
        if (result.mResultCode == ResultCode.ADD_FRIEND_ALLOW) {
            this.addOneFriend(result.mDstUsername, result.mDstIconIndex, true)
            mFriendCount.value = super.getString(R.string.IDS_FRIEND_COUNT, mClient.friendCount)
            message = String.format(message, result.mDstUsername)
            Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
            ChatActivity.addFriend(result.mDstUsername)
        } else if (result.mResultCode == ResultCode.ALREADY_BE_FRIENDS || result.mResultCode == ResultCode.ADD_FRIEND_NOT_ALLOW || result.mResultCode == ResultCode.USER_NOT_FOUND) {
            message = result.mDstUsername + message
            Toast.makeText(this, message, Toast.LENGTH_LONG).show()
        }
    }

    /**
     * 得到登录结果事件的响应方法。
     * @param result    登录结果
     */
    private fun onGetLogonResult(result: LogonResult) {
        if (result.mResultCode == ResultCode.LOGON_SUCCEEDED) {
            this.changeState(true)
            this.addAllFriends(result)
            for (userInfo in result.mFriends) {
                ChatActivity.addFriend(userInfo.mUsername)
            }
        } else {
            val message = this.getResultMessage(result.mResultCode)
            Toast.makeText(this, message, Toast.LENGTH_LONG).show()
        }
    }

    /**
     * 得到注册结果事件的响应方法。
     * @param result    注册结果
     */
    private fun onGetRegResult(result: RegResult) {
        val message = this.getResultMessage(result.mResultCode)
        if (result.mResultCode == ResultCode.REG_SUCCEEDED) {
            this.changeState(true)
            Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
        } else {
            Toast.makeText(this, message, Toast.LENGTH_LONG).show()
        }
    }

    /**
     * 单击好友列表控件的响应方法。
     * @param username  用户名
     */
    private val onItemClick = fun(username: String) {
        // 取消系统通知
        val manager = super.getSystemService(NOTIFICATION_SERVICE) as NotificationManager
        manager.cancel(Const.NOTIFICATION_ID_CHAT)

        // 生成意图
        val intent = Intent(this, ChatActivity::class.java)

        // 将好友名保存到意图中
        intent.putExtra(Const.KEY_FRIEND_NAME, username)

        // 回调
        super.startActivityForResult(intent, Const.UM_CHAT_C2S)
    }

    /**
     * 按键事件的响应方法。
     * @param keyCode   按键
     * @param e         事件相关信息
     * @return 事件在此被处理则返回 true，否则返回 false
     */
    override fun onKeyDown(keyCode: Int, e: KeyEvent): Boolean {
        if (keyCode == KeyEvent.KEYCODE_BACK) {
            super.moveTaskToBack(false)
            return true
        }
        return super.onKeyDown(keyCode, e)
    }

    /**
     * "添加好友"菜单项的单击响应方法。
     */
    private fun onMenuItemAddFriendClicked() {
        mInputBox.show(
            tipText = super.getString(R.string.IDS_PLEASE_INPUT_USERNAME),
            onOKString = {
                if (TextUtils.isEmpty(it)) {
                    return@show
                }
                val resultCode = mClient.addFriend(it)
                if (resultCode != ResultCode.SUCCEEDED) {
                    val message = getResultMessage(resultCode)
                    Toast.makeText(this@MainActivity, message, Toast.LENGTH_LONG).show()
                }
            }
        )
    }

    /**
     * 所有菜单项的单击响应方法。
     * @param menuItem  用户单击的菜单项
     * @return 事件在此被处理则返回 true，否则返回 false
     */
    override fun onMenuItemClick(menuItem: MenuItem): Boolean {
        when (menuItem.itemId) {
            R.id.IDC_MENU_ITEM_LOGON -> this.onMenuItemLogonClicked()
            R.id.IDC_MENU_ITEM_REG -> this.onMenuItemRegClicked()
            R.id.IDC_MENU_ITEM_ADD_FRIEND -> this.onMenuItemAddFriendClicked()
            R.id.IDC_MENU_ITEM_MCHAT -> this.onMenuItemMChatClicked()
            R.id.IDC_MENU_ITEM_LOGOFF -> this.onMenuItemLogoffClicked()
            else -> return false
        }
        return true
    }

    /**
     * "离线"菜单项的单击响应方法。
     */
    private fun onMenuItemLogoffClicked() {
        // 设置各种控件的状态
        this.changeState(false)

        // 清空各种列表
        mListViewUsers.clear()
        ChatActivity.clear()

        // 发送离线请求
        mClient.logoff()
    }

    /**
     * "登录"菜单项的单击响应方法。
     */
    private fun onMenuItemLogonClicked() {
        mLogonDialog.show { username, password ->
            mClient.logon(username, password)
        }
    }

    /**
     * "群发消息"菜单项的单击响应方法。
     */
    private fun onMenuItemMChatClicked() {
        // 取消系统通知
        val manager = super.getSystemService(NOTIFICATION_SERVICE) as NotificationManager
        manager.cancel(Const.NOTIFICATION_ID_CHAT)

        // 生成意图
        val intent = Intent(this, ChatActivity::class.java)

        // 将"群发消息"保存到意图中
        intent.putExtra(Const.KEY_FRIEND_NAME, ImProtocol.MULTI_CHAT)

        // 显示聊天窗口
        super.startActivityForResult(intent, Const.UM_CHAT_C2S)
    }

    /**
     * "注册"菜单项的单击响应方法。
     */
    private fun onMenuItemRegClicked() {
        val intent = Intent(this, RegActivity::class.java)
        super.startActivityForResult(intent, Const.RC_REG)
    }
}
